#include "Eventloop.h"
#include "EventloopProxy.h"
#include "IOchannel.h"
#include "log/Logger.h"


#include "utility/assertion.h"
#include "wrap/eventfd.h"
#include "wrap/unistd.h"



namespace _ {

static thread_local Eventloop *loopOfCurrentThread = nullptr;

}


Eventloop *Eventloop::LOOP_OF_CURRENT_THREAD() {
    return _::loopOfCurrentThread;
}

Eventloop::Eventloop():
    _mutex{},
    _pendingFuncs{},
    _eventloopProxy{},
    _timerManager{},
    _tid{CurrentThread::tid()},
    _callingPendingFunc{false},
    _looping{false},
    _loopOver{false},
    _quit{false}
{
    LOG_DEBUG << "Eventloop " << this << "created in thread" << _tid;
    if (_::loopOfCurrentThread != nullptr) {
        LOG_FATAL << "Another loop " << _::loopOfCurrentThread
                  << " existed in this thread " << _tid;
    }
    else {
        _::loopOfCurrentThread = this;
    }
    _eventloopProxy = std::make_unique<EventloopProxy>(*this);
    _timerManager = std::make_unique<TimerManager>(*this);

}

Eventloop::~Eventloop() {
    LOG_DEBUG << "Eventloop " << this << " of this thread" << _tid
              << " destructs in thread " << CurrentThread::tid();
    _::loopOfCurrentThread = nullptr;
}

void Eventloop::loop() {
    assert(!_looping);
    ASSERT_IN_THIS_THREAD();
    _looping = true;
    _loopOver = false;
    _quit = false;
    LOG_VERBOSE << "Eventloop " << this << " start looping";
    while (!_quit) {
        _eventloopProxy->poll_event();
    }
    LOG_VERBOSE << "Eventloop " << this << "stop looping";
    _looping = false;
    _loopOver = true;
}

void Eventloop::assert_in_this_thread(const char *func, const char *file, int line) const {
    if (is_in_this_thread()) {
        return;
    }
    LOG_FATAL << "Eventloop " << this << " was created in " << _tid
              << ", current tid=" << CurrentThread::tid() << " in " << func
              << "() of " << file << ":" << line;
}

bool Eventloop::is_in_this_thread() const {
    return _tid == CurrentThread::tid();
}

void Eventloop::quit() {
    assert(!_quit);
    _quit = true;
    if (!is_in_this_thread()) {
        // wakeup();
    }
}

void Eventloop::run_in_loop(const TrivialFunc &func) {
    if (!is_in_this_thread()) {
        // queue_in_loop(func);
        return;
    }
    assert(func);
    func();
}


void Eventloop::cancel(const TimerID &timerid) {
    _timerManager->cancel(timerid);
}

TimerID Eventloop::run_after(double delay, const TrivialFunc &callback) {
    return _timerManager->add(callback, Utility::cast_duration(delay), true);
}

TimerID Eventloop::run_every(double delay, const TrivialFunc &callback) {
    return _timerManager->add(callback, Utility::cast_duration(delay), false);
}